package com.ljs.module.entity.template.upgrade;

import com.ljs.module.annotation.TemplateKey;
import com.ljs.module.common.TypeEnum;
import com.ljs.module.entity.BaseEntity;
import com.ljs.module.entity.ConfigProperties;
import com.ljs.module.util.FileUtil;
import com.ljs.module.util.TemplateUtil;
import com.ljs.module.util.UpgradeUtil;
import com.ljs.module.util.Util;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@TemplateKey
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Upgrade extends BaseEntity {
    private String path;
    private String type;
    private String module;
    private String[] configs;
    private MultipartFile[] files;

    @TemplateKey
    private String tableName;
    @TemplateKey
    private String entityName;

    private List<UpgradeTable> tableData;

    // 数据库字段集合
    @TemplateKey
    private List<String> fields = new ArrayList<>();
    // 字段类型集合
    @TemplateKey
    private List<String> types = new ArrayList<>();
    // 主键集合
    @TemplateKey
    private List<String> priFields = new ArrayList<>();
    // 是否为空
    @TemplateKey
    private List<String> isNulls = new ArrayList<>();

    @TemplateKey("fieldMsgs")
    private Map<String, FieldMessage> fieldMessageMap = new HashMap<>();

    @TemplateKey("package")
    private String packageName;
    @TemplateKey
    private String nowVersion;
    @TemplateKey
    private String nextVersion;
    @TemplateKey
    private String createDate = getNowDate();
    @TemplateKey
    private boolean createIdClass;



    public void init() throws Exception {
        setConfigProperties(ConfigProperties.of(configs));
        UpgradeUtil.changeModule(path, module);
        String basePath = UpgradeUtil.basicDir;
        packageName = UpgradeUtil.packageName;
        String[] versions = getNewVersion(basePath);
        nowVersion = versions[0];
        nextVersion = versions[1].replaceAll("_", ".");
        if (versions[0].equals("New")) {
            FileUtil.directoryNotExistThenMake(basePath + File.separator + grade.get(type));
        }

        if (configProperties.isBuildTable()) {
            // 表名转小写
            tableName = Util.toLowerCase(tableName.trim());
            // 过滤掉字段名为空且所有字段名转小写
            tableData = tableData.stream().filter(x -> !StringUtils.isBlank(x.getField())).map(x -> {
                x.setField(Util.toLowerCase(x.getField()));
                return x;
            }).collect(Collectors.toList());

            String[] split = Util.containThenSplit(tableName);
            tableName = split[0];
            entityName = (split[1].charAt(0) + "").toUpperCase() + split[1].substring(1);

            for (int i = 0; i < tableData.size(); i++) {
                UpgradeTable data = tableData.get(i);

                if (!StringUtils.isBlank(data.getField())) {
                    String field = data.getField();
                    split = Util.containThenSplit(field);
                    fields.add(split[0]);
                    String valueType = "ValueType." + data.getType();
                    String entityField = split[1];

                    FieldMessage fieldMessage = new FieldMessage()
                            .setFieldName(entityField)
                            .setValueType(valueType)
                            .setIsNull("" + !data.isIsnull());
                    String method = ("" + entityField.charAt(0)).toUpperCase() + entityField.substring(1);
                    fieldMessage.setMethodGet("get" + method)
                            .setMethodSet("set" + method);

                    ConversionValueType convert = UpgradeUtil.fieldClass.get(valueType);
                    List<String> annotations = new ArrayList<>();
                    if (data.isPrikey()) {
                        annotations.add("@Id");
                        priFields.add(split[0]);
                    }
                    annotations.add("@Column(name = \"" + split[0] + "\")");
                    String[] specialHandle = convert.getSpecialHandle();
                    if (specialHandle != null && specialHandle.length > 0) {
                        annotations.addAll(Arrays.asList(specialHandle));
                    }
                    fieldMessage.setClassType(convert.getType())
                            .setClassPackage(convert.getClassPackage())
                            .setAnnotation(annotations.toArray(new String[]{}));
                    fieldMessageMap.put(split[0], fieldMessage);
                    types.add(valueType);
                    isNulls.add("" + !data.isIsnull());
                }
            }
            createIdClass = priFields.size() > 1;
        }
    }

    public String build() throws Exception {
        init();
        StringBuilder resMsg = new StringBuilder();
        try {
            String template = TypeEnum.valueOf(type).getTemplate();
            Map<String, Object> templateKeyORM = TemplateUtil.getTemplateKeyORM(this);
            String render = TemplateUtil.render(template, templateKeyORM);
            String fileName = task.get(type) + "_" + nowVersion;
            resMsg.append(FileUtil.insertFile(UpgradeUtil.basicDir + File.separator + grade.get(type) + File.separator + fileName + ".java", render));
            if (files != null && files.length > 0) {
                for (MultipartFile file : files) {
                    StringBuilder stringBuilder = new StringBuilder();
                    if (file != null && !file.isEmpty()) {
                        String uploadFileName = file.getOriginalFilename();
                        if (uploadFileName.contains(".xml")) {
                            String filePath = UpgradeUtil.basicDir + File.separator + grade.get(type) + File.separator + fileName + ".xml";
                            File dest = new File(filePath);
                            try {
                                file.transferTo(dest);
                                resMsg.append(uploadFileName + "上传成功，对应版本号:" + fileName + ".xml<br>");
                            } catch (IOException e) {
                                resMsg.append(uploadFileName + "上传失败:写入文件失败<br>");
                            }
                        } else {
                            resMsg.append(uploadFileName + "上传失败:上传格式错误！<br>");
                        }
                    }
                }
            }
            if (configProperties.isBuildTable()) {
                // 无文件创建升级类
                if (configProperties.isBuildEntity()) {
                    FileUtil.directoryNotExistThenMake(UpgradeUtil.basicDir + File.separator + "entity");
                    String entity = "upgrade" + File.separator + "entity.js";
                    render = TemplateUtil.render(entity, templateKeyORM);
                    resMsg.append(FileUtil.insertFile(UpgradeUtil.basicDir + File.separator + "entity" + File.separator + entityName + ".java", render));

                    if (createIdClass) {
                        String ids = "upgrade" + File.separator + "idsentity.js";
                        List<FieldMessage> fieldMessages = new ArrayList<>();
                        for (String priField : priFields) {
                            fieldMessages.add(fieldMessageMap.get(priField));
                        }

                        Set<String> importPackages = fieldMessages.stream()
                                .filter(x -> !x.getClassPackage().contains("java.lang"))
                                .map(x -> x.getClassPackage()).collect(Collectors.toSet());
                        templateKeyORM.put("idsFieldMsgs", fieldMessages);
                        templateKeyORM.put("importPackages", importPackages);
                        render = TemplateUtil.render(ids, templateKeyORM);
                        resMsg.append(FileUtil.insertFile(UpgradeUtil.basicDir + File.separator + "entity" + File.separator + entityName + "IdsEntity.java", render));
                    }
                    if (configProperties.isBuildEntityDAO()) {
                        FileUtil.directoryNotExistThenMake(UpgradeUtil.basicDir + File.separator + "dao");
                        String dao = "upgrade" + File.separator + "entitydao.js";
                        render = TemplateUtil.render(dao, templateKeyORM);
                        resMsg.append(FileUtil.insertFile(UpgradeUtil.basicDir + File.separator + "dao" + File.separator + entityName + "DAO.java", render));

                        UpgradeUtil.insertPojoToModule(this);
                    }
                }
            }
            resMsg.append("创建升级类成功");
        } catch (Exception e) {
            System.out.println(e.getMessage() + e);
        }
        return resMsg.toString();
    }

    public static Map<String, String> grade = new HashMap<>();
    public static Map<String, String> task = new HashMap<>();

    static {
        grade.put(TypeEnum.UpgradeTask.toString(), "upgrade");
        grade.put(TypeEnum.PostTask.toString(), "postupgrade");
        task.put(TypeEnum.UpgradeTask.toString(), "UpgradeTask");
        task.put(TypeEnum.PostTask.toString(), "PostTask");
    }

    public List<String> getNowVersions(String basePath) {
        File file = new File(basePath + File.separator + grade.get(type));
        if (!file.exists()) {
            return new ArrayList<>();
        }
        return Arrays.stream(file.listFiles(x -> x.getName().contains(task.get(type)) && x.getName().contains(".java")))
                .map(x -> {
                    String fileName = x.getName();
                    String version = fileName.substring(fileName.indexOf("_") + 1, fileName.lastIndexOf("."));
                    return version.equals("New") ? "0_0_0" : version;
                }).sorted((x, y) -> Util.versionSort(x, y))
                .collect(Collectors.toList());
    }

    public String[] getNewVersion(String basePath) {
        List<String> nowVersions = getNowVersions(basePath);
        if (nowVersions == null || nowVersions.size() == 0) {
            return new String[]{"New", "0_0_1"};
        }
        if (nowVersions.size() == 1) {
            return new String[]{"0_0_1", "0_0_2"};
        }
        String lastVersion = nowVersions.get(0);
        for (int i = 1; i < nowVersions.size(); i++) {
            lastVersion = Util.versionCompare(lastVersion, nowVersions.get(i));
        }
        String lastV = lastVersion.substring(lastVersion.lastIndexOf("_") + 1);
        Integer newV = Integer.parseInt(lastV) + 1;
        Integer nextNewV = newV + 1;
        String prefix = lastVersion.substring(0, lastVersion.lastIndexOf("_") + 1);
        return new String[]{prefix + newV, prefix + nextNewV};
    }

    public String getNowDate() {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return df.format(new Date());
    }
}
